package com.yupi.yupicturebackend.utils;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.yupi.yupicturebackend.model.dto.picture.PictureHeatmapData;
import com.yupi.yupicturebackend.model.dto.picture.PictureStatistics;
import com.yupi.yupicturebackend.model.dto.picture.TrendAnalysis;
import com.yupi.yupicturebackend.model.dto.picture.UserBehaviorStats;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 图片统计分析工具类
 * 
 * <p>提供图片热度分析、用户行为统计、趋势预测等数据分析功能</p>
 * 
 * @author yupi
 */
@Slf4j
@Component
public class PictureStatisticsUtils {

    /**
     * 计算图片热度分数
     *
     * @param viewCount 浏览次数
     * @param downloadCount 下载次数
     * @param shareCount 分享次数
     * @param likeCount 点赞次数
     * @param commentCount 评论次数
     * @param uploadTime 上传时间
     * @return 热度分数
     */
    public static double calculateHeatScore(long viewCount, long downloadCount, long shareCount, 
                                          long likeCount, long commentCount, Date uploadTime) {
        // 基础权重配置
        double viewWeight = 1.0;
        double downloadWeight = 3.0;
        double shareWeight = 5.0;
        double likeWeight = 2.0;
        double commentWeight = 4.0;
        
        // 计算基础分数
        double baseScore = viewCount * viewWeight + 
                          downloadCount * downloadWeight + 
                          shareCount * shareWeight + 
                          likeCount * likeWeight + 
                          commentCount * commentWeight;
        
        // 时间衰减因子（越新的图片权重越高）
        long daysSinceUpload = (System.currentTimeMillis() - uploadTime.getTime()) / (1000 * 60 * 60 * 24);
        double timeDecayFactor = Math.exp(-daysSinceUpload / 30.0); // 30天半衰期
        
        // 最终热度分数
        return baseScore * timeDecayFactor;
    }

    /**
     * 生成图片热度排行榜
     *
     * @param pictureStats 图片统计数据列表
     * @param topN 返回前N名
     * @return 热度排行榜
     */
    public static List<PictureStatistics> generateHeatRanking(List<PictureStatistics> pictureStats, int topN) {
        if (CollUtil.isEmpty(pictureStats)) {
            return new ArrayList<>();
        }
        
        return pictureStats.stream()
            .sorted((a, b) -> Double.compare(b.getHeatScore(), a.getHeatScore()))
            .limit(topN)
            .collect(Collectors.toList());
    }

    /**
     * 分析用户行为模式
     *
     * @param userActions 用户行为数据
     * @return 用户行为统计
     */
    public static UserBehaviorStats analyzeUserBehavior(List<Map<String, Object>> userActions) {
        UserBehaviorStats stats = new UserBehaviorStats();
        
        if (CollUtil.isEmpty(userActions)) {
            return stats;
        }
        
        // 按行为类型统计
        Map<String, Long> actionTypeCount = userActions.stream()
            .collect(Collectors.groupingBy(
                action -> (String) action.get("actionType"),
                Collectors.counting()
            ));
        
        stats.setActionTypeDistribution(actionTypeCount);
        
        // 按时间段统计
        Map<String, Long> hourlyDistribution = userActions.stream()
            .collect(Collectors.groupingBy(
                action -> {
                    Date actionTime = (Date) action.get("actionTime");
                    return String.valueOf(DateUtil.hour(actionTime, true));
                },
                Collectors.counting()
            ));
        
        stats.setHourlyDistribution(hourlyDistribution);
        
        // 计算活跃度指标
        long totalActions = userActions.size();
        long uniqueUsers = userActions.stream()
            .map(action -> (String) action.get("userId"))
            .collect(Collectors.toSet())
            .size();
        
        stats.setTotalActions(totalActions);
        stats.setUniqueUsers(uniqueUsers);
        stats.setAvgActionsPerUser(uniqueUsers > 0 ? (double) totalActions / uniqueUsers : 0);
        
        // 分析最活跃时段
        String peakHour = hourlyDistribution.entrySet().stream()
            .max(Map.Entry.comparingByValue())
            .map(Map.Entry::getKey)
            .orElse("0");
        stats.setPeakActiveHour(Integer.parseInt(peakHour));
        
        return stats;
    }

    /**
     * 生成趋势分析报告
     *
     * @param historicalData 历史数据
     * @param days 分析天数
     * @return 趋势分析结果
     */
    public static TrendAnalysis analyzeTrend(List<Map<String, Object>> historicalData, int days) {
        TrendAnalysis analysis = new TrendAnalysis();
        
        if (CollUtil.isEmpty(historicalData)) {
            return analysis;
        }
        
        // 按日期分组统计
        Map<String, Long> dailyStats = historicalData.stream()
            .collect(Collectors.groupingBy(
                data -> DateUtil.formatDate((Date) data.get("date")),
                Collectors.counting()
            ));
        
        analysis.setDailyStats(dailyStats);
        
        // 计算增长率
        List<String> sortedDates = dailyStats.keySet().stream()
            .sorted()
            .collect(Collectors.toList());
        
        if (sortedDates.size() >= 2) {
            String firstDate = sortedDates.get(0);
            String lastDate = sortedDates.get(sortedDates.size() - 1);
            
            long firstValue = dailyStats.get(firstDate);
            long lastValue = dailyStats.get(lastDate);
            
            double growthRate = firstValue > 0 ? 
                ((double) (lastValue - firstValue) / firstValue) * 100 : 0;
            analysis.setGrowthRate(growthRate);
        }
        
        // 预测未来趋势
        List<Double> values = sortedDates.stream()
            .map(date -> dailyStats.get(date).doubleValue())
            .collect(Collectors.toList());
        
        double predictedValue = predictNextValue(values);
        analysis.setPredictedNextValue(predictedValue);
        
        // 趋势方向
        analysis.setTrendDirection(determineTrendDirection(values));
        
        return analysis;
    }

    /**
     * 生成热力图数据
     *
     * @param pictureData 图片数据
     * @return 热力图数据
     */
    public static List<PictureHeatmapData> generateHeatmapData(List<Map<String, Object>> pictureData) {
        List<PictureHeatmapData> heatmapData = new ArrayList<>();
        
        if (CollUtil.isEmpty(pictureData)) {
            return heatmapData;
        }
        
        // 按位置和时间统计
        Map<String, Map<String, Long>> locationTimeStats = new HashMap<>();
        
        for (Map<String, Object> data : pictureData) {
            String location = (String) data.getOrDefault("location", "unknown");
            Date time = (Date) data.get("uploadTime");
            String timeSlot = DateUtil.format(time, "yyyy-MM-dd HH");
            
            locationTimeStats.computeIfAbsent(location, k -> new HashMap<>())
                .merge(timeSlot, 1L, Long::sum);
        }
        
        // 转换为热力图数据格式
        for (Map.Entry<String, Map<String, Long>> locationEntry : locationTimeStats.entrySet()) {
            String location = locationEntry.getKey();
            
            for (Map.Entry<String, Long> timeEntry : locationEntry.getValue().entrySet()) {
                PictureHeatmapData heatData = new PictureHeatmapData();
                heatData.setLocation(location);
                heatData.setTimeSlot(timeEntry.getKey());
                heatData.setValue(timeEntry.getValue());
                heatData.setIntensity(calculateIntensity(timeEntry.getValue()));
                heatmapData.add(heatData);
            }
        }
        
        return heatmapData;
    }

    /**
     * 计算图片质量分布
     *
     * @param pictures 图片列表
     * @return 质量分布统计
     */
    public static Map<String, Object> analyzeQualityDistribution(List<Map<String, Object>> pictures) {
        Map<String, Object> distribution = new HashMap<>();
        
        if (CollUtil.isEmpty(pictures)) {
            return distribution;
        }
        
        // 按分辨率分类
        Map<String, Long> resolutionStats = pictures.stream()
            .collect(Collectors.groupingBy(
                pic -> categorizeResolution((Integer) pic.get("width"), (Integer) pic.get("height")),
                Collectors.counting()
            ));
        
        distribution.put("resolutionDistribution", resolutionStats);
        
        // 按文件大小分类
        Map<String, Long> sizeStats = pictures.stream()
            .collect(Collectors.groupingBy(
                pic -> categorizeFileSize((Long) pic.get("fileSize")),
                Collectors.counting()
            ));
        
        distribution.put("fileSizeDistribution", sizeStats);
        
        // 按格式分类
        Map<String, Long> formatStats = pictures.stream()
            .collect(Collectors.groupingBy(
                pic -> (String) pic.get("format"),
                Collectors.counting()
            ));
        
        distribution.put("formatDistribution", formatStats);
        
        // 计算平均值
        double avgWidth = pictures.stream()
            .mapToInt(pic -> (Integer) pic.get("width"))
            .average()
            .orElse(0);
        
        double avgHeight = pictures.stream()
            .mapToInt(pic -> (Integer) pic.get("height"))
            .average()
            .orElse(0);
        
        double avgFileSize = pictures.stream()
            .mapToLong(pic -> (Long) pic.get("fileSize"))
            .average()
            .orElse(0);
        
        distribution.put("avgWidth", avgWidth);
        distribution.put("avgHeight", avgHeight);
        distribution.put("avgFileSize", avgFileSize);
        
        return distribution;
    }

    /**
     * 生成用户偏好分析
     *
     * @param userInteractions 用户交互数据
     * @return 用户偏好分析结果
     */
    public static Map<String, Object> analyzeUserPreferences(List<Map<String, Object>> userInteractions) {
        Map<String, Object> preferences = new HashMap<>();
        
        if (CollUtil.isEmpty(userInteractions)) {
            return preferences;
        }
        
        // 分析颜色偏好
        Map<String, Long> colorPreferences = userInteractions.stream()
            .filter(interaction -> interaction.containsKey("dominantColor"))
            .collect(Collectors.groupingBy(
                interaction -> (String) interaction.get("dominantColor"),
                Collectors.counting()
            ));
        
        preferences.put("colorPreferences", colorPreferences);
        
        // 分析标签偏好
        Map<String, Long> tagPreferences = new HashMap<>();
        for (Map<String, Object> interaction : userInteractions) {
            @SuppressWarnings("unchecked")
            List<String> tags = (List<String>) interaction.get("tags");
            if (tags != null) {
                for (String tag : tags) {
                    tagPreferences.merge(tag, 1L, Long::sum);
                }
            }
        }
        
        preferences.put("tagPreferences", tagPreferences);
        
        // 分析时间偏好
        Map<String, Long> timePreferences = userInteractions.stream()
            .collect(Collectors.groupingBy(
                interaction -> {
                    Date time = (Date) interaction.get("interactionTime");
                    int hour = DateUtil.hour(time, true);
                    if (hour >= 6 && hour < 12) return "morning";
                    else if (hour >= 12 && hour < 18) return "afternoon";
                    else if (hour >= 18 && hour < 24) return "evening";
                    else return "night";
                },
                Collectors.counting()
            ));
        
        preferences.put("timePreferences", timePreferences);
        
        return preferences;
    }

    /**
     * 计算相关性分析
     *
     * @param data1 数据集1
     * @param data2 数据集2
     * @return 相关系数
     */
    public static double calculateCorrelation(List<Double> data1, List<Double> data2) {
        if (data1.size() != data2.size() || data1.isEmpty()) {
            return 0.0;
        }
        
        double mean1 = data1.stream().mapToDouble(Double::doubleValue).average().orElse(0);
        double mean2 = data2.stream().mapToDouble(Double::doubleValue).average().orElse(0);
        
        double numerator = 0.0;
        double sumSq1 = 0.0;
        double sumSq2 = 0.0;
        
        for (int i = 0; i < data1.size(); i++) {
            double diff1 = data1.get(i) - mean1;
            double diff2 = data2.get(i) - mean2;
            
            numerator += diff1 * diff2;
            sumSq1 += diff1 * diff1;
            sumSq2 += diff2 * diff2;
        }
        
        double denominator = Math.sqrt(sumSq1 * sumSq2);
        return denominator == 0 ? 0 : numerator / denominator;
    }

    // ==================== 私有辅助方法 ====================

    /**
     * 预测下一个值（简单线性回归）
     */
    private static double predictNextValue(List<Double> values) {
        if (values.size() < 2) {
            return values.isEmpty() ? 0 : values.get(0);
        }
        
        int n = values.size();
        double sumX = 0, sumY = 0, sumXY = 0, sumX2 = 0;
        
        for (int i = 0; i < n; i++) {
            sumX += i;
            sumY += values.get(i);
            sumXY += i * values.get(i);
            sumX2 += i * i;
        }
        
        double slope = (n * sumXY - sumX * sumY) / (n * sumX2 - sumX * sumX);
        double intercept = (sumY - slope * sumX) / n;
        
        return slope * n + intercept;
    }

    /**
     * 判断趋势方向
     */
    private static String determineTrendDirection(List<Double> values) {
        if (values.size() < 2) {
            return "stable";
        }
        
        double first = values.get(0);
        double last = values.get(values.size() - 1);
        
        double changeRate = (last - first) / first;
        
        if (changeRate > 0.1) return "increasing";
        else if (changeRate < -0.1) return "decreasing";
        else return "stable";
    }

    /**
     * 计算热力图强度
     */
    private static double calculateIntensity(long value) {
        // 简单的对数缩放
        return Math.log(value + 1) / Math.log(100);
    }

    /**
     * 分类分辨率
     */
    private static String categorizeResolution(int width, int height) {
        long pixels = (long) width * height;
        
        if (pixels >= 8000000) return "4K+";
        else if (pixels >= 2000000) return "Full HD";
        else if (pixels >= 1000000) return "HD";
        else return "SD";
    }

    /**
     * 分类文件大小
     */
    private static String categorizeFileSize(long fileSize) {
        if (fileSize >= 10 * 1024 * 1024) return "Large (>10MB)";
        else if (fileSize >= 1024 * 1024) return "Medium (1-10MB)";
        else if (fileSize >= 100 * 1024) return "Small (100KB-1MB)";
        else return "Tiny (<100KB)";
    }
}
